function Harvester (battle) {
	// Harvester is the level 1 enemy
	// It's slow, don't aggressively attack, just move around, and find crystal to harvest.
	// Its attack range is very short, don't deal much damage, and only attack when it get attacked by the penguin.
	
	// Misc info
	var HARVESTER_SIZE_W = 80; // Image size of the harvester
	var HARVESTER_SIZE_H = 80; // Image size of the harvester

	var HARVESTER_OFFSET_X = (MAP_TILE_SIZE - HARVESTER_SIZE_W) * 0.5; // Offset from the top-left corner of the image, to where the actual harvester image is
	var HARVESTER_OFFSET_Y = (MAP_TILE_SIZE - HARVESTER_SIZE_H) * 0.5; // Offset from the top-left corner of the image, to where the actual harvester image is
	
	var HARVESTER_SPEED = MAP_TILE_SIZE * 0.001; // The move speed of the harvester
	var HARVESTER_ATTACK_PARTICLE_EFFECT = 1;
	var HARVESTER_ATTACK_PARTICLE_EFFECT_LIFE_TIME = 500;
	
	// AI decision
	var HARVESTER_AI_WANDER = 0;            // Move around aimlessly
	var HARVESTER_AI_GO_TO_HARVEST = 1;     // Follow the A* path to a mineral block. After that, switch to mining animation
	var HARVESTER_AI_HARVEST = 2;           // Stand still and mine. If get attacked, switch to attack the attacker
	var HARVESTER_AI_ATTACK_TARGET = 3;     // Attack the penguin
	var HARVESTER_AI_ATTACK = 4;     // Attack the penguin
	
	// Direction enum
	var DIRECTION_DOWN = 0;   // Down
	var DIRECTION_LEFT = 1;   // Left
	var DIRECTION_UP = 2;     // Up
	var DIRECTION_RIGHT = 3;  // Right
	
	
	// The harvester have 3 states. Moving, attacking and harvesting.
	var HARVESTER_STATE_MOVING = 0;
	var HARVESTER_STATE_ATTACKING = 1;
	var HARVESTER_STATE_HARVESTING = 2;
	
	var HARVESTER_STATE_DYING = 9;
	
	// Animation count
	var HARVESTER_ANIMATION_COUNT_MOVING = 4;           // Number of frame in moving animation
	var HARVESTER_ANIMATION_COUNT_ATTACKING = 4;        // Number of frame in attacking animation
	var HARVESTER_ANIMATION_COUNT_HARVESTING = 4;       // Number of frame in harvesting animation
	
	var HARVESTER_ANIMATION_COUNT_DYING = 1;           // Number of frame in moving animation
	
	
	var HARVESTER_MOVE_FRAME_LENGTH = 150;              // The duration of each frame in moving animation
	var HARVESTER_HARVESTING_FRAME_LENGTH = 150;        // The duration of each frame in harvesting animation
	var HARVESTER_ATTACKING_FRAME_LENGTH = 150;        // The duration of each frame in harvesting animation
	
	
	var HARVESTER_ATTACK_FRAME_W = 150;
	var HARVESTER_ATTACK_FRAME_H = 40;
	var HARVESTER_ATTACK_FRAME_LENGTH = 75;
	var HARVESTER_ATTACK_ANIMATION_COUNT = 8;
	
	// Properties
	var HARVESTER_MAX_HP = 100;
	var HARVESTER_ATTACK_RANGE = 250;
	var HARVESTER_ATTACK_DAMAGE = 10;

	// These are the MUST HAVE properties.
	this.m_x = 0;             // Position x
	this.m_y = 0;             // Position y
	this.m_direction = 0;     // Direction
	this.m_HP = 0;            // Hit point
	this.m_abnormalStatus = 0;        // State of the enemy, stun, freeze, or ....
	
	
	this.m_cx = 0;
	this.m_cy = 0;
	
	
	// Additional properties
	this.m_actionStatus = 0;         // The animation state (moving, or attacking...)
	
	var animationCount = 0;   // This is used to count the duration before switching to the new frame in the animation
	this.m_animationStep = 0; // This is the frame index in the animation
	
	// For AI:
	this.m_intendToDo = 0;             // What the harvester will do next
	var harvestTimeCount = 0;
	
	var HARVESTER_CHANGE_MIND_CHANCE = 0.05;        // The chance which the harvester will stop doing what it's doing, and decide to do something else.
	
	var HARVESTER_AI_WANDER_DECIDE_CHANCE = 0.2;   // All decision chance need to have total of 1
	var HARVESTER_AI_HARVEST_DECIDE_CHANCE = 0.7;
	var HARVESTER_AI_ATTACK_DECIDE_CHANCE = 0.1;
	
	var HARVESTER_AI_RETRY_COUNT = 5;              // Number of retry when search for a resource node
	var HARVESTER_AI_HARVESTING_TIME = 8000;       // Time the harvester will harvest one resource node
	
	var HARVESTER_AI_DYING_TIME = 200;       // Time the harvester will harvest one resource node
	var dyingTimeCount = 0;
	
	var mustRevenge = 0;
	
	// For fighting
	var allowMove = true;
	var attackingTarget = null;
	var coolDownCount = 0;
	var distanceToTarget = 0;
	var HARVESTER_ATTACK_COOLDOWN = 1000;
	
	// Path finding
	var pathMap = null;                // Path map from the battle object
	var pathGrid = null;               // The path grid contain a 2D array (1 and 0) to define movable square
	var pathFinder = null;             // A* path finder object
	var pathWayPoint = null;           // The result waypoint after the path finding
	var pathWayPointProgress = 0;      // Which node in the waypoint is the harvester in
	var pathWayPointLength = 0;        // Total number of node in the waypoint
	
	// Image
	var spriteImage = g_graphicEngine.LoadImage("Data/ActionPhase/Enemy/Harvester/Harvester.png");
	var attackImage = g_graphicEngine.LoadImage("Data/ActionPhase/Enemy/Harvester/Attack.png");
	
	// Init source position in the image
	var actionSource = new Array();
	for (var i=HARVESTER_STATE_MOVING; i<=HARVESTER_STATE_HARVESTING; i++) {
		actionSource[i] = new Array();
		for (var j=DIRECTION_DOWN; j<=DIRECTION_RIGHT; j++) {
			actionSource[i][j] = new Array();
		}
	}
	
	actionSource[HARVESTER_STATE_DYING] = new Array();
	for (var j=DIRECTION_DOWN; j<=DIRECTION_RIGHT; j++) {
		actionSource[HARVESTER_STATE_DYING][j] = new Array();
	}
	
	// Hard-code the source info for all animation
	// Moving
	for (var i=DIRECTION_DOWN; i<=DIRECTION_RIGHT; i++) {
		for (var j=0; j<=HARVESTER_ANIMATION_COUNT_MOVING; j++) {
			actionSource[HARVESTER_STATE_MOVING][i][j] = new SourceRect (spriteImage, HARVESTER_SIZE_W * j, HARVESTER_SIZE_H * i, HARVESTER_SIZE_W, HARVESTER_SIZE_H);
		}
	}
	
	// Harvesting
	for (var i=DIRECTION_DOWN; i<=DIRECTION_RIGHT; i++) {
		for (var j=0; j<=HARVESTER_ANIMATION_COUNT_HARVESTING; j++) {
			actionSource[HARVESTER_STATE_HARVESTING][i][j] = new SourceRect (spriteImage, HARVESTER_SIZE_W * j + HARVESTER_SIZE_W * 4, HARVESTER_SIZE_H * i, HARVESTER_SIZE_W, HARVESTER_SIZE_H);
		}
	}
	
	// Attacking
	for (var i=DIRECTION_DOWN; i<=DIRECTION_RIGHT; i++) {
		for (var j=0; j<=HARVESTER_ANIMATION_COUNT_ATTACKING; j++) {
			actionSource[HARVESTER_STATE_ATTACKING][i][j] = new SourceRect (spriteImage, HARVESTER_SIZE_W * j, HARVESTER_SIZE_H * (i + 4), HARVESTER_SIZE_W, HARVESTER_SIZE_H);
		}
	}
	
	
	
	// Dying
	for (var i=DIRECTION_DOWN; i<=DIRECTION_RIGHT; i++) {
		for (var j=0; j<=HARVESTER_ANIMATION_COUNT_DYING; j++) {
			actionSource[HARVESTER_STATE_DYING][i][j] = new SourceRect (spriteImage, HARVESTER_SIZE_W * j, HARVESTER_SIZE_H * i, HARVESTER_SIZE_W, HARVESTER_SIZE_H);
		}
	}
	
	
	// HPBar
	var HP_BAR_W = 60;
	var HP_BAR_H = 5;
	var HP_BAR_OFFSET_X = 0;
	var HP_BAR_OFFSET_Y = 0;
	var hpBar = g_graphicEngine.LoadImage("Data/ActionPhase/UI/SmallHPBar.png");
	
	
	this.Init = function () {
		// Get the path map pointer from the battle object
		pathMap = battle.pathMap;
		
		// Init the path grid based on that path map to used in path finding
		pathGrid = new PF.Grid (MAP_SIZE_W, MAP_SIZE_H);
		for (var i=0; i<MAP_SIZE_W; i++) {
			for (var j=0; j<MAP_SIZE_H; j++) {
				if (pathMap[i][j] > GROUND_EMPTY)  
					pathGrid.setWalkableAt(i, j, false);
			}
		}
		
		// Init the A* path finder
		pathFinder = new PF.AStarFinder();
		
		// Hit point to max
		this.m_HP = HARVESTER_MAX_HP;
		
		this.m_cx = ((this.m_x / MAP_TILE_SIZE) + 0.5) >> 0;
		this.m_cy = ((this.m_y / MAP_TILE_SIZE) + 0.5) >> 0;
		this.DecideWhatToDo();
	}
	
	
	
	this.Update = function () {
		if (this.m_actionStatus != HARVESTER_STATE_DYING) {
			if (this.m_intendToDo == HARVESTER_AI_WANDER)
				this.m_actionStatus = HARVESTER_STATE_MOVING;
			else if (this.m_intendToDo == HARVESTER_AI_GO_TO_HARVEST)
				this.m_actionStatus = HARVESTER_STATE_MOVING;
			else if (this.m_intendToDo == HARVESTER_AI_HARVEST)
				this.m_actionStatus = HARVESTER_STATE_HARVESTING;
			else if (this.m_intendToDo == HARVESTER_AI_ATTACK_TARGET)
				this.m_actionStatus = HARVESTER_STATE_MOVING;
			else if (this.m_intendToDo = HARVESTER_AI_ATTACK) {
				this.m_actionStatus = HARVESTER_STATE_ATTACKING;
			}
		}
		
		
		this.UpdateAnimation();
			
		if (this.m_actionStatus == HARVESTER_STATE_MOVING) {
			this.Move();
		}
		else if (this.m_actionStatus == HARVESTER_STATE_HARVESTING) {
			harvestTimeCount += g_deltaTime;
			if (harvestTimeCount > HARVESTER_AI_HARVESTING_TIME) {
				this.DecideWhatToDo();
			}
			if (mustRevenge) {
				coolDownCount = 0;
				animationCount = 0;
				this.m_animationStep = 0;
				this.DecideWhatToDo (HARVESTER_AI_ATTACK_TARGET);
				mustRevenge = false;
			}
		}
		else if (this.m_actionStatus == HARVESTER_STATE_ATTACKING) {
			this.Attack();
		}
		else if (this.m_actionStatus == HARVESTER_STATE_DYING) {
			dyingTimeCount += g_deltaTime;
			if (dyingTimeCount > HARVESTER_AI_DYING_TIME) {
				battle.RemoveEnemy (this);
			}
		}
	}
	
	
	
	
	this.TakeDamage = function (damage) {
		this.m_HP -= damage;
		if (this.m_HP <= 0) {
			this.m_HP = 0;
			this.m_actionStatus = HARVESTER_STATE_DYING;
			animationCount = 0;
			this.m_animationStep = 0;
			
			battle.StartExplosion (3, this.m_x + MAP_TILE_SIZE * 0.5, this.m_y + MAP_TILE_SIZE * 0.5, 0, 0);
		}
		mustRevenge = true;
	}
	
	
	
	this.UpdateAnimation = function () {
		// Update the animation frame based on what it is doing
		// We increase animation count based on deltaTime, when it's reach the frame length
		// We reset it, and switch to next frame.
		
		if (this.m_actionStatus == HARVESTER_STATE_MOVING) {
			animationCount += g_deltaTime;
			if (animationCount >= HARVESTER_MOVE_FRAME_LENGTH) {
				animationCount -= HARVESTER_MOVE_FRAME_LENGTH;
				if (animationCount > HARVESTER_MOVE_FRAME_LENGTH) {
					animationCount = 0;
				}
				
				this.m_animationStep ++;
				if (this.m_animationStep >= HARVESTER_ANIMATION_COUNT_MOVING) {
					this.m_animationStep = 0;
				}
			}
		}
		else if (this.m_actionStatus == HARVESTER_STATE_HARVESTING) {
			animationCount += g_deltaTime;
			if (animationCount >= HARVESTER_HARVESTING_FRAME_LENGTH) {
				animationCount -= HARVESTER_HARVESTING_FRAME_LENGTH;
				if (animationCount > HARVESTER_HARVESTING_FRAME_LENGTH) {
					animationCount = 0;
				}
				
				this.m_animationStep ++;
				if (this.m_animationStep >= HARVESTER_ANIMATION_COUNT_HARVESTING) {
					this.m_animationStep = 0;
				}
			}
		}
		else if (this.m_actionStatus == HARVESTER_STATE_ATTACKING) {
			animationCount += g_deltaTime;
			if (animationCount >= HARVESTER_ATTACKING_FRAME_LENGTH) {
				animationCount -= HARVESTER_ATTACKING_FRAME_LENGTH;
				if (animationCount > HARVESTER_ATTACKING_FRAME_LENGTH) {
					animationCount = 0;
				}
				
				this.m_animationStep ++;
				if (this.m_animationStep >= HARVESTER_ANIMATION_COUNT_ATTACKING) {
					this.m_animationStep = HARVESTER_ANIMATION_COUNT_ATTACKING - 1;
				}
			}
		}
	}
	
	
	
	this.Attack = function () {
		coolDownCount += g_deltaTime;
		if (coolDownCount >= HARVESTER_ATTACK_COOLDOWN) {
			coolDownCount = 0;
			animationCount = 0;
			this.m_animationStep = 0;
			this.m_intendToDo = HARVESTER_AI_ATTACK_TARGET;
		}
	}
	
	
	this.Move = function () {
		// Move first
		if (allowMove) {
			if      (this.m_direction == DIRECTION_DOWN)  this.m_y += HARVESTER_SPEED * g_deltaTime;
			else if (this.m_direction == DIRECTION_LEFT)  this.m_x -= HARVESTER_SPEED * g_deltaTime;
			else if (this.m_direction == DIRECTION_UP) 	  this.m_y -= HARVESTER_SPEED * g_deltaTime;
			else if (this.m_direction == DIRECTION_RIGHT) this.m_x += HARVESTER_SPEED * g_deltaTime;
		}
		
		// Get the approximately cell position of the harvester
		this.m_cx = ((this.m_x / MAP_TILE_SIZE) + 0.5) >> 0;
		this.m_cy = ((this.m_y / MAP_TILE_SIZE) + 0.5) >> 0;
	
		// Depend on purpose, think when we reach a cell
		if (Math.abs(this.m_x - this.m_cx * MAP_TILE_SIZE) < HARVESTER_SPEED * g_deltaTime
		&&  Math.abs(this.m_y - this.m_cy * MAP_TILE_SIZE) < HARVESTER_SPEED * g_deltaTime) {
			if (mustRevenge) {
				coolDownCount = 0;
				animationCount = 0;
				this.m_animationStep = 0;
				this.DecideWhatToDo (HARVESTER_AI_ATTACK_TARGET);
				mustRevenge = false;
			}
			else {
				this.CheckCollision();
			}
		}
	}
	
	
	this.CheckCollision = function () {
		if (this.m_intendToDo == HARVESTER_AI_WANDER) {
			// If moving aimlessly, continue to move, if reach obstacle, stop, and think what to do again.
			if (this.m_direction == DIRECTION_DOWN) {
				if (this.m_cy == MAP_SIZE_H - 1) {
					this.m_x = this.m_cx * MAP_TILE_SIZE;
					this.m_y = this.m_cy * MAP_TILE_SIZE;
					this.DecideWhatToDo();
					return;
				}
				else if (pathMap[this.m_cx][this.m_cy+1] > GROUND_EMPTY) {
					this.m_x = this.m_cx * MAP_TILE_SIZE;
					this.m_y = this.m_cy * MAP_TILE_SIZE;
					this.DecideWhatToDo();
					return;
				}
			}
			else if (this.m_direction == DIRECTION_LEFT) {
				if (this.m_cx == 0) {
					this.m_x = this.m_cx * MAP_TILE_SIZE;
					this.m_y = this.m_cy * MAP_TILE_SIZE;
					this.DecideWhatToDo();
					return;
				}
				else if (pathMap[this.m_cx-1][this.m_cy] > GROUND_EMPTY) {
					this.m_x = this.m_cx * MAP_TILE_SIZE;
					this.m_y = this.m_cy * MAP_TILE_SIZE;
					this.DecideWhatToDo();
					return;
				}
			}
			else if (this.m_direction == DIRECTION_UP) {
				if (this.m_cy == 0) {
					this.m_x = this.m_cx * MAP_TILE_SIZE;
					this.m_y = this.m_cy * MAP_TILE_SIZE;
					this.DecideWhatToDo();
					return;
				}
				else if (pathMap[this.m_cx][this.m_cy-1] > GROUND_EMPTY) {
					this.m_x = this.m_cx * MAP_TILE_SIZE;
					this.m_y = this.m_cy * MAP_TILE_SIZE;
					this.DecideWhatToDo();
					return;
				}
			}
			else if (this.m_direction == DIRECTION_RIGHT) {
				if (this.m_cx == MAP_SIZE_W - 1) {
					this.m_x = this.m_cx * MAP_TILE_SIZE;
					this.m_y = this.m_cy * MAP_TILE_SIZE;
					this.DecideWhatToDo();
					return;
				}
				else if (pathMap[this.m_cx+1][this.m_cy] > GROUND_EMPTY) {
					this.m_x = this.m_cx * MAP_TILE_SIZE;
					this.m_y = this.m_cy * MAP_TILE_SIZE;
					this.DecideWhatToDo();
					return;
				}
			}
			
			if (Math.random() < HARVESTER_CHANGE_MIND_CHANCE) {
				this.m_x = this.m_cx * MAP_TILE_SIZE;
				this.m_y = this.m_cy * MAP_TILE_SIZE;
				this.DecideWhatToDo();
				return;
			}
		}
		else if (this.m_intendToDo == HARVESTER_AI_GO_TO_HARVEST) {
			if (this.m_cx == pathWayPoint[pathWayPointProgress][0]
			&&  this.m_cy == pathWayPoint[pathWayPointProgress][1]) {
				pathWayPointProgress ++;
				
				if (pathWayPointProgress == pathWayPointLength) {
					this.m_intendToDo = HARVESTER_AI_HARVEST;
					harvestTimeCount = 0;
					
					if      (this.m_cx > 0 && pathMap[this.m_cx-1][this.m_cy] == GROUND_RESOURCE)               this.m_direction = DIRECTION_LEFT;
					else if (this.m_cx < MAP_SIZE_W - 1 && pathMap[this.m_cx+1][this.m_cy] == GROUND_RESOURCE)  this.m_direction = DIRECTION_RIGHT;
					else if (this.m_cy > 0 && pathMap[this.m_cx][this.m_cy-1] == GROUND_RESOURCE)               this.m_direction = DIRECTION_UP;
					else if (this.m_cy < MAP_SIZE_H - 1 && pathMap[this.m_cx][this.m_cy+1] == GROUND_RESOURCE)  this.m_direction = DIRECTION_DOWN;
				}
				else {
					var oldDirection = this.m_direction;
					var newX = pathWayPoint[pathWayPointProgress][0];
					var newY = pathWayPoint[pathWayPointProgress][1];
					
					if      (newX > this.m_cx) this.m_direction = DIRECTION_RIGHT;
					else if (newX < this.m_cx) this.m_direction = DIRECTION_LEFT;
					else if (newY > this.m_cy) this.m_direction = DIRECTION_DOWN;
					else if (newY < this.m_cy) this.m_direction = DIRECTION_UP;
					
					if (oldDirection != this.m_direction) {
						this.m_x = this.m_cx * MAP_TILE_SIZE;
						this.m_y = this.m_cy * MAP_TILE_SIZE;
					}
				}
			}
		}
		else if (this.m_intendToDo == HARVESTER_AI_ATTACK_TARGET) {
			pathWayPointLength = 0;
			
			if (Math.random() < HARVESTER_CHANGE_MIND_CHANCE) {
				this.m_x = this.m_cx * MAP_TILE_SIZE;
				this.m_y = this.m_cy * MAP_TILE_SIZE;
				this.DecideWhatToDo();
				return;
			}
			
			// Check to see if the target is within range
			// If it is, attack.
			if (Math.abs(this.m_x - attackingTarget.m_x) <= MAP_TILE_SIZE * 0.5) {
				if (attackingTarget.m_y > this.m_y && attackingTarget.m_y < this.m_y + HARVESTER_ATTACK_RANGE) {
					distanceToTarget = attackingTarget.m_y - this.m_y;
					attackingTarget.TakeDamage(HARVESTER_ATTACK_DAMAGE);
					g_emitterManager.AddEmitter (HARVESTER_ATTACK_PARTICLE_EFFECT, this.m_x + MAP_TILE_SIZE * 0.5, this.m_y + distanceToTarget, HARVESTER_ATTACK_PARTICLE_EFFECT_LIFE_TIME);
					this.m_direction = DIRECTION_DOWN;
					this.m_intendToDo = HARVESTER_AI_ATTACK;
					allowMove = false;
					return;
				}
				else if (attackingTarget.m_y < this.m_y && attackingTarget.m_y > this.m_y - HARVESTER_ATTACK_RANGE) {
					distanceToTarget = this.m_y - attackingTarget.m_y;
					attackingTarget.TakeDamage(HARVESTER_ATTACK_DAMAGE);
					g_emitterManager.AddEmitter (HARVESTER_ATTACK_PARTICLE_EFFECT, this.m_x + MAP_TILE_SIZE * 0.5, this.m_y - distanceToTarget, HARVESTER_ATTACK_PARTICLE_EFFECT_LIFE_TIME);
					this.m_direction = DIRECTION_UP;
					this.m_intendToDo = HARVESTER_AI_ATTACK;
					allowMove = false;
					return;
				}
			}
			
			if (Math.abs(this.m_y - attackingTarget.m_y) <= MAP_TILE_SIZE * 0.5) {
				if (attackingTarget.m_x > this.m_x && attackingTarget.m_x < this.m_x + HARVESTER_ATTACK_RANGE) {
					distanceToTarget = attackingTarget.m_x - this.m_x;
					attackingTarget.TakeDamage(HARVESTER_ATTACK_DAMAGE);
					g_emitterManager.AddEmitter (HARVESTER_ATTACK_PARTICLE_EFFECT, this.m_x + MAP_TILE_SIZE * 0.5 + distanceToTarget, this.m_y, HARVESTER_ATTACK_PARTICLE_EFFECT_LIFE_TIME);
					this.m_direction = DIRECTION_RIGHT;
					this.m_intendToDo = HARVESTER_AI_ATTACK;
					allowMove = false;
					return;
				}
				else if (attackingTarget.m_x < this.m_x && attackingTarget.m_x > this.m_x - HARVESTER_ATTACK_RANGE) {
					distanceToTarget = this.m_x - attackingTarget.m_x;
					attackingTarget.TakeDamage(HARVESTER_ATTACK_DAMAGE);
					g_emitterManager.AddEmitter (HARVESTER_ATTACK_PARTICLE_EFFECT, this.m_x + MAP_TILE_SIZE * 0.5 - distanceToTarget, this.m_y, HARVESTER_ATTACK_PARTICLE_EFFECT_LIFE_TIME);
					this.m_direction = DIRECTION_LEFT;
					this.m_intendToDo = HARVESTER_AI_ATTACK;
					allowMove = false;
					return;
				}
			}
			
			FindPath (this.m_cx, this.m_cy, ((attackingTarget.m_x / MAP_TILE_SIZE) + 0.5) >> 0, ((attackingTarget.m_y / MAP_TILE_SIZE) + 0.5) >> 0);
			
			if (pathWayPointLength > 1) {
				var oldDirection = this.m_direction;
				var newX = pathWayPoint[1][0];
				var newY = pathWayPoint[1][1];
				
				if      (newX > this.m_cx) this.m_direction = DIRECTION_RIGHT;
				else if (newX < this.m_cx) this.m_direction = DIRECTION_LEFT;
				else if (newY > this.m_cy) this.m_direction = DIRECTION_DOWN;
				else if (newY < this.m_cy) this.m_direction = DIRECTION_UP;
				
				if (oldDirection != this.m_direction) {
					this.m_x = this.m_cx * MAP_TILE_SIZE;
					this.m_y = this.m_cy * MAP_TILE_SIZE;
				}
				
				allowMove = true;
			}
			else {
				this.m_x = this.m_cx * MAP_TILE_SIZE;
				this.m_y = this.m_cy * MAP_TILE_SIZE;
				
				allowMove = false;
			}
		}
	}
	
	this.Stop = function () {
		
	}
	
	
	this.DecideWhatToDo = function (decision) {
		// This is the core of the AI decision tree.
		// The harvester will pick a purpose first. Then assign command accordingly.
		if (decision == null) {
			var chance = Math.random();
			if (chance < HARVESTER_AI_WANDER_DECIDE_CHANCE) {
				decision = HARVESTER_AI_WANDER;
			}
			else if (chance < HARVESTER_AI_WANDER_DECIDE_CHANCE + HARVESTER_AI_HARVEST_DECIDE_CHANCE) {
				decision = HARVESTER_AI_GO_TO_HARVEST;
			}
			else if (chance < HARVESTER_AI_WANDER_DECIDE_CHANCE + HARVESTER_AI_HARVEST_DECIDE_CHANCE + HARVESTER_AI_ATTACK_DECIDE_CHANCE) {
				decision = HARVESTER_AI_ATTACK_TARGET;
			}
		}
		
		
		if (decision == HARVESTER_AI_WANDER) {
			// OK, wander around
			var oldDirection = this.m_direction;
			var directionArray = [];
				directionArray.push (DIRECTION_DOWN);
				directionArray.push (DIRECTION_LEFT);
				directionArray.push (DIRECTION_UP);
				directionArray.push (DIRECTION_RIGHT);
			
			if (this.m_cy+1 >= MAP_SIZE_H || pathMap[this.m_cx][this.m_cy+1] > GROUND_EMPTY) {
				for (var i=0; i<directionArray.length; i++) {
					if (directionArray[i] == DIRECTION_DOWN) directionArray.splice (i, 1);
				}
			}
			if (this.m_cx-1 < 0 || pathMap[this.m_cx-1][this.m_cy] > GROUND_EMPTY) {
				for (var i=0; i<directionArray.length; i++) {
					if (directionArray[i] == DIRECTION_LEFT) directionArray.splice (i, 1);
				}
			}
			if (this.m_cy-1 < 0 || pathMap[this.m_cx][this.m_cy-1] > GROUND_EMPTY) {
				for (var i=0; i<directionArray.length; i++) {
					if (directionArray[i] == DIRECTION_UP) directionArray.splice (i, 1);
				}
			}
			if (this.m_cx+1 >= MAP_SIZE_W || pathMap[this.m_cx-1][this.m_cy] > GROUND_EMPTY) {
				for (var i=0; i<directionArray.length; i++) {
					if (directionArray[i] == DIRECTION_RIGHT) directionArray.splice (i, 1);
				}
			}
			
			if (directionArray.length == 0) {
				allowMove = false;
			}
			else {
				var chance = (Math.random() * directionArray.length) >> 0
				this.m_direction = directionArray[chance]; //  Pick a new direction
				allowMove = true;
			}
			
			this.m_intendToDo = HARVESTER_AI_WANDER; //Don't know what to do yet, just wander around then...
			
			
			if (oldDirection != this.m_direction) {
				this.m_x = this.m_cx * MAP_TILE_SIZE;
				this.m_y = this.m_cy * MAP_TILE_SIZE;
			}
		}
		else if (decision == HARVESTER_AI_GO_TO_HARVEST) {
			// It decide to go harvesting
			// Find a random resource point on the map
			// Scan through all square to find a square which adjacent to a resource node
			var suitableSquareX = new Array();
			var suitableSquareY = new Array();
			for (var i=0; i<MAP_SIZE_W; i++) {
				for (var j=0; j<MAP_SIZE_H; j++) {
					if (pathMap[i][j] == GROUND_RESOURCE) {
						if (i > 0 && pathMap[i-1][j] == GROUND_EMPTY) {
							var add = true;
							for (var k=0; k<suitableSquareX.length; k++) {
								if (suitableSquareX[k] == i-1 && suitableSquareY[k] == j) {
									add = false;
								}
							}
							if (add) {
								suitableSquareX.push (i-1); suitableSquareY.push (j);
							}
						}
						if (i < MAP_SIZE_W - 1 && pathMap[i+1][j] == GROUND_EMPTY) {
							var add = true;
							for (var k=0; k<suitableSquareX.length; k++) {
								if (suitableSquareX[k] == i+1 && suitableSquareY[k] == j) {
									add = false;
								}
							}
							if (add) {
								suitableSquareX.push (i+1); suitableSquareY.push (j);
							}
						}
						if (j > 0 && pathMap[i][j-1] == GROUND_EMPTY) {
							var add = true;
							for (var k=0; k<suitableSquareX.length; k++) {
								if (suitableSquareX[k] == i && suitableSquareY[k] == j-1) {
									add = false;
								}
							}
							if (add) {
								suitableSquareX.push (i); suitableSquareY.push (j+1);
							}
						}
						if (j < MAP_SIZE_H - 1 && pathMap[i][j+1] == GROUND_EMPTY) {
							var add = true;
							for (var k=0; k<suitableSquareX.length; k++) {
								if (suitableSquareX[k] == i-1 && suitableSquareY[k] == j) {
									add = false;
								}
							}
							if (add) {
								suitableSquareX.push (i); suitableSquareY.push (j+1);
							}
						}
					}
				}
			}
			
			var retryCount = 0;
			pathWayPointLength = 0;
			while (pathWayPointLength == 0) {
				if (suitableSquareX.length == 0) {
					// If there is no resource node
					this.DecideWhatToDo (HARVESTER_AI_WANDER);
					return;
				}
				else {
					var pickIndex = (Math.random() * suitableSquareX.length) >> 0;
					FindPath (this.m_cx, this.m_cy, suitableSquareX[pickIndex], suitableSquareY[pickIndex]);
					if (pathWayPointLength == 0) {
						retryCount ++;
						suitableSquareX.splice (pickIndex, 1);
						suitableSquareY.splice (pickIndex, 1);
						
						if (retryCount > HARVESTER_AI_RETRY_COUNT) {
							// If can't pick a resource node, wander instead
							this.DecideWhatToDo (HARVESTER_AI_WANDER);
							return;
						}
					}
					else if (pathWayPointLength == 1) {
						this.DecideWhatToDo (HARVESTER_AI_WANDER);
						return;
					}
					else {
						pathWayPointProgress = 1;
						
						var newX = pathWayPoint[1][0];
						var newY = pathWayPoint[1][1];
						
						if      (newX > this.m_cx) this.m_direction = DIRECTION_RIGHT;
						else if (newX < this.m_cx) this.m_direction = DIRECTION_LEFT;
						else if (newY > this.m_cy) this.m_direction = DIRECTION_DOWN;
						else if (newY < this.m_cy) this.m_direction = DIRECTION_UP;
						
						this.m_intendToDo = HARVESTER_AI_GO_TO_HARVEST;
						allowMove = true;
					}
				}
			}
		}
		else if (decision == HARVESTER_AI_ATTACK_TARGET) {
			attackingTarget = battle.m_penguin[(Math.random() * battle.m_penguin.length) >> 0];
			this.m_intendToDo = HARVESTER_AI_ATTACK_TARGET;
			allowMove = false;
		}
	}
	
	

	this.Draw = function () {
		// Draw the harvester on screen
		g_graphicEngine.Draw (g_context, actionSource[this.m_actionStatus][this.m_direction][this.m_animationStep].m_id, actionSource[this.m_actionStatus][this.m_direction][this.m_animationStep].m_x, actionSource[this.m_actionStatus][this.m_direction][this.m_animationStep].m_y,
			actionSource[this.m_actionStatus][this.m_direction][this.m_animationStep].m_w, actionSource[this.m_actionStatus][this.m_direction][this.m_animationStep].m_h, this.m_x + HARVESTER_OFFSET_X + BATTLE_OFFSET_X, this.m_y + HARVESTER_OFFSET_Y + BATTLE_OFFSET_Y, HARVESTER_SIZE_W, HARVESTER_SIZE_H, 1);
			
		// Draw the HP Bar
		g_graphicEngine.Draw (g_context, hpBar, 0, 0, HP_BAR_W, HP_BAR_H, this.m_x + HP_BAR_OFFSET_X + BATTLE_OFFSET_X, this.m_y + HARVESTER_OFFSET_Y + HP_BAR_OFFSET_Y, HP_BAR_W, HP_BAR_H);
		g_graphicEngine.Draw (g_context, hpBar, 0, HP_BAR_H, (HP_BAR_W * (this.m_HP / HARVESTER_MAX_HP)) >> 0, HP_BAR_H, this.m_x + HP_BAR_OFFSET_X + BATTLE_OFFSET_X, this.m_y + HARVESTER_OFFSET_Y + HP_BAR_OFFSET_Y, (HP_BAR_W * (this.m_HP / HARVESTER_MAX_HP)) >> 0, HP_BAR_H);
		
		// Draw the lighting beam
		if (coolDownCount > 0) {
			var attackFrame = (coolDownCount / HARVESTER_ATTACK_FRAME_LENGTH) >> 0;
			if (attackFrame < HARVESTER_ATTACK_ANIMATION_COUNT) {
				//g_graphicEngine.SetDrawModeAddActive (g_context, true);
				if (this.m_direction == DIRECTION_RIGHT) {
					g_graphicEngine.Draw (g_context, attackImage, 0, HARVESTER_ATTACK_FRAME_H * attackFrame, HARVESTER_ATTACK_FRAME_W, HARVESTER_ATTACK_FRAME_H, 
						this.m_x + BATTLE_OFFSET_X + MAP_TILE_SIZE, this.m_y + HP_BAR_OFFSET_Y,
						distanceToTarget, HARVESTER_ATTACK_FRAME_H, 1, 0, 0, 0);
				}
				else if (this.m_direction == DIRECTION_DOWN) {
					g_graphicEngine.Draw (g_context, attackImage, 0, HARVESTER_ATTACK_FRAME_H * attackFrame, HARVESTER_ATTACK_FRAME_W, HARVESTER_ATTACK_FRAME_H, 
						this.m_x + BATTLE_OFFSET_X - (distanceToTarget - HARVESTER_ATTACK_FRAME_H) * 0.5 + (MAP_TILE_SIZE - HARVESTER_ATTACK_FRAME_H) * 0.5, this.m_y + HP_BAR_OFFSET_Y + MAP_TILE_SIZE + (distanceToTarget - HARVESTER_ATTACK_FRAME_H) * 0.5,
						distanceToTarget, HARVESTER_ATTACK_FRAME_H, 1, 0, 0, 90);
				}
				else if (this.m_direction == DIRECTION_LEFT) {
					g_graphicEngine.Draw (g_context, attackImage, 0, HARVESTER_ATTACK_FRAME_H * attackFrame, HARVESTER_ATTACK_FRAME_W, HARVESTER_ATTACK_FRAME_H, 
						this.m_x + BATTLE_OFFSET_X - distanceToTarget, this.m_y + HP_BAR_OFFSET_Y,
						distanceToTarget, HARVESTER_ATTACK_FRAME_H, 1, 0, 0, 180);
				}
				else if (this.m_direction == DIRECTION_UP) {
					g_graphicEngine.Draw (g_context, attackImage, 0, HARVESTER_ATTACK_FRAME_H * attackFrame, HARVESTER_ATTACK_FRAME_W, HARVESTER_ATTACK_FRAME_H, 
						this.m_x + BATTLE_OFFSET_X - (distanceToTarget - HARVESTER_ATTACK_FRAME_H) * 0.5 + (MAP_TILE_SIZE - HARVESTER_ATTACK_FRAME_H) * 0.5, this.m_y + HP_BAR_OFFSET_Y - distanceToTarget + (distanceToTarget - HARVESTER_ATTACK_FRAME_H) * 0.5,
						distanceToTarget, HARVESTER_ATTACK_FRAME_H, 1, 0, 0, 270);
				}
				//g_graphicEngine.SetDrawModeAddActive (g_context, false);
			}
		}
	}
	
	
	
	
	
	
	
	
	
	
	
	
	
	// PATH FINDER -------------------------------------------------------------
	var FindPath = function (sx, sy, dx, dy) {
		pathWayPoint = pathFinder.findPath (sx, sy, dx, dy, pathGrid.clone());
		pathWayPointProgress = 0;
		pathWayPointLength = pathWayPoint.length;
	}
	// PATH FINDER -------------------------------------------------------------
}
